{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Erprobe Ziffernerkennung\n", "\n", "Hier wird der Code aus dem Notebook \"02 Erkennung von Ziffern.ipynb\" geladen.\n", "Die trainierte Ziffernerkennung wird in eine Anwendung eingebettet." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true, "tags": [] }, "outputs": [], "source": [ "%%capture\n", "%run \"02 Erkennung von Ziffern.ipynb\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(f\"Genauigkeit von k nächste Nachbarn: {neigh.score(X_test, y_test):.02%}\")\n", "print(f\"Genauigkeit vom Random Forest: {clf.score(X_test, y_test):.02%}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bette diese Prädiktoren nun in eine Anwendung ein." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import PIL\n", "import PIL.ImageDraw\n", "import tkinter\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Skaliere Bild auf 8x8 Pixel und wandle es in einen 1d-Array um, damit es als Eingabe für die ML-Algorithmen verwendet werden kann." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def resize_image(pil_image):\n", " \"resizes a PIL image to 8x8 pixels and scales the intensity values to 0..16\"\n", " resized_digit_image = pil_image.resize((8, 8), PIL.Image.Resampling.LANCZOS)\n", " resized_digit_array = np.array(resized_digit_image)\n", " new_100_percent = np.partition(resized_digit_array.flatten(), -9)[-9]\n", " rescaled_digit_repr = (\n", " (resized_digit_array - resized_digit_array.min()) / (new_100_percent - resized_digit_array.min())\n", " ) * 16\n", " np.clip(rescaled_digit_repr, 0, 16, out=rescaled_digit_repr)\n", " return rescaled_digit_repr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Definiere eine kleine einfache Tkinter-Anwendung für eine Zifferneingabe." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "class App:\n", " width = 300\n", " height = 300\n", " output_image = PIL.Image.new(\"L\", (width, height))\n", " center = height // 2\n", " white = (255, 255, 255)\n", "\n", " def __init__(self):\n", " self.main = tkinter.Tk()\n", " self.canvas = tkinter.Canvas(self.main, width=self.width, height=self.height, bg='white')\n", " self.canvas.pack()\n", " self.draw = PIL.ImageDraw.Draw(self.output_image)\n", " self.canvas.pack(expand=tkinter.YES, fill=tkinter.BOTH)\n", " self.canvas.bind(\"\", self.paint)\n", " button_left = tkinter.Button(text=\"predict\", command=self.execute_estimator)\n", " button_left.pack(side='left')\n", " button_right = tkinter.Button(text=\"clear\", command=lambda: [\n", " self.canvas.delete(\"all\"), self.label_text_link.set(\"\\n\")])\n", " button_right.pack(side='left')\n", " self.label_text_link = tkinter.StringVar()\n", " self.label_text_link.set(\"\\n\")\n", " label = tkinter.Label(self.main, textvariable=self.label_text_link)\n", " label.pack()\n", "\n", " def paint(self, event):\n", " x1, y1 = (event.x - 1), (event.y - 1)\n", " x2, y2 = (event.x + 1), (event.y + 1)\n", " self.canvas.create_oval(x1, y1, x2, y2, fill=\"white\", width=5)\n", " self.draw.line([x1, y1, x2, y2], fill=\"white\", width=5)\n", "\n", " def execute_estimator(self):\n", " rescaled_digit_repr = resize_image(self.output_image)\n", " plt.imshow(rescaled_digit_repr)\n", " plt.show()\n", " try:\n", " digit_category_rf = clf.predict([rescaled_digit_repr.flatten()])\n", " digit_category_knn = neigh.predict([rescaled_digit_repr.flatten()])\n", " prediction_output_as_text = f\"RF predicted: {digit_category_rf[0]}\\nKNN predicted: {digit_category_knn[0]}\"\n", " except ValueError as e:\n", " prediction_output_as_text = f\"Encountered a problem:\\n{str(e)[:20]}...\"\n", " print(prediction_output_as_text)\n", " self.label_text_link.set(prediction_output_as_text)\n", " self.output_image = PIL.Image.new(\"L\", (self.width, self.height))\n", " self.draw = PIL.ImageDraw.Draw(self.output_image)\n", "\n", " def run(self):\n", " self.main.mainloop()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Starte Tkinter-Applikation.\n", "Diese geht in einem neuen Fenster auf, welches unabhängig vom Browser ist, in welchem dieses Jupyter Notebook angezeigt wird.\n", "Die Applikation ist ein kleines Fenster, in dem man mit der Maus Ziffern schreiben kann.\n", "Mit dem Klick auf `predict` werden dann die ML-Modelle zur Vorhersage genutzt.\n", "Unten wird für jede Vorhersage die Umwandlung des Inputs als 8x8-Matrix angezeigt." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "App().run()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Creative     Dieses Werk von Marvin Kastner ist lizenziert unter einer Creative Commons Namensnennung 4.0 International Lizenz." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.1" }, "toc-autonumbering": false, "toc-showcode": false, "toc-showmarkdowntxt": false }, "nbformat": 4, "nbformat_minor": 4 }